﻿using System;
using System.IO;
using System.Reflection;

namespace Netfraction.Common.Logging
{
    public class TextDataStore
    {
        private static string _applicationDataDir;

        private string _dataStoreName;
        private DataSource _owner;
        private string _basePath;

        /// <summary>
        /// Creates a new TextDataStore instance and the specified data store. Does not overwrite an existing store.
        /// </summary>
        /// <param name="owner"></param>
        /// <param name="storeName"></param>
        public TextDataStore(DataSource owner, string storeName)
        {
            this._dataStoreName = storeName;
            this._owner = owner;

            if (string.IsNullOrEmpty(_applicationDataDir))
            {
                Assembly curAssembly = System.Reflection.Assembly.GetEntryAssembly();
                string curCompany = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), GetAssemblyCompany(curAssembly));
                _applicationDataDir = System.IO.Path.Combine(curCompany, GetProductName(curAssembly));
            }

            this._basePath = Path.Combine(_applicationDataDir, this.Owner.Name + "." + this.Owner.Guid.ToString() + Path.DirectorySeparatorChar +
                this.Owner.Version + Path.DirectorySeparatorChar);

            Create(storeName, false);
        }

        public bool Create(string name, bool overwrite)
        {
            if (!CheckBasePath(name))
                return false;

            if (!overwrite && File.Exists(Path.Combine(this.BasePath, name)))
                return true;

            if (!Directory.Exists(Path.GetDirectoryName(Path.Combine(this.BasePath, name))))
                Directory.CreateDirectory(Path.GetDirectoryName(Path.Combine(this.BasePath, name)));

            FileStream f = File.Create(Path.Combine(this.BasePath, name));
            f.Close();
            this.DataStoreName = name;

            return true;
        }

        public StreamReader CreateReader()
        {
            if (!CheckFileExists())
                return null;

            try
            {
                return new StreamReader(new FileStream(this.FullPath, FileMode.Open, FileAccess.Read, FileShare.Read));
            }
            catch (FileNotFoundException fnfex)
            {
                System.Diagnostics.Debug.Write(fnfex.Message);
                return null;
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.Write(ex.Message);
                return null;
            }
        }

        public StreamWriter CreateWriter()
        {
            if (!CheckFileExists())
                return null;

            try
            {
                if (!File.Exists(this.FullPath))
                    return File.CreateText(this.FullPath);

                return new StreamWriter(new FileStream(this.FullPath, FileMode.Append, FileAccess.Write, FileShare.None));
            }
            catch (FileNotFoundException fnfex)
            {
                System.Diagnostics.Debug.Write(fnfex.Message);
                return null;
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.Write(ex.Message);
                return null;
            }
        }

        // if the name is a path, make sure it's root is in the data path.
        protected bool CheckBasePath(string name)
        {
            if (!Path.GetFullPath(Path.Combine(this.BasePath, name)).StartsWith(this.BasePath))
                return false;
            else
                return true;
        }

        public bool IsEmpty()
        {
            FileInfo f = new FileInfo(this.FullPath);

            if (f.Length == 0)
                return true;
            else
                return false;
        }

        private bool CheckFileExists()
        {
            if (string.IsNullOrEmpty(this.DataStoreName))
                return false;

            if (!File.Exists(this.FullPath) && !Create(this.DataStoreName, false))
                return false;

            return true;
        }

        public bool Delete()
        {
            if (this.DataStoreName == string.Empty)
                return false;

            File.Delete(this.FullPath);

            return File.Exists(this.FullPath);
        }

        public DataSource Owner
        {
            get { return _owner; }
            set
            {
                if (string.IsNullOrEmpty(_owner.Version))
                    _owner.Version = "";

                _owner = value;
            }
        }

        public string FullPath
        {
            get
            {
                if (string.IsNullOrEmpty(_dataStoreName))
                    return string.Empty;

                return Path.Combine(_basePath, _dataStoreName);
            }
        }

        public string BasePath
        {
            get { return _basePath; }
        }

        public string DataStoreName
        {
            get { return _dataStoreName; }
            set { _dataStoreName = value; }
        }

        #region GetAppDir

        /// <summary>
        /// Gets the name of the product.
        /// </summary>
        /// <param name="assembly">The assembly.</param>
        /// <returns></returns>
        public static string GetProductName(Assembly assembly)
        {
            string productName = "";

            if (Attribute.IsDefined(assembly, typeof(AssemblyProductAttribute)))
            {
                AssemblyProductAttribute asProductName = (AssemblyProductAttribute)Attribute.GetCustomAttribute(assembly, typeof(AssemblyProductAttribute));
                productName = asProductName.Product;
            }

            return productName;
        }

        /// <summary>
        /// Gets the assembly company.
        /// </summary>
        /// <param name="assembly">The assembly.</param>
        /// <returns></returns>
        public static string GetAssemblyCompany(Assembly assembly)
        {
            string company = "";

            if (Attribute.IsDefined(assembly, typeof(AssemblyCompanyAttribute)))
            {
                AssemblyCompanyAttribute ascompany = (AssemblyCompanyAttribute)Attribute.GetCustomAttribute(assembly, typeof(AssemblyCompanyAttribute));
                company = ascompany.Company;
            }

            return company;
        }

        #endregion
    }
}
